﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; 
using System.Web;
using System.Data.Entity.Infrastructure;
using Taobao.Tools2.Domain;
using System.Data.Entity;

namespace Taobao.Tools2.Domain.EntityFramework
{
    #region Class EntityRepository<T>
    public class EntityRepository<T> : IRepository<T>
        where T : class
    {
        #region Ctor

        public EntityRepository(EfDbContextBase dbContext)
        {
            m_DbContext = dbContext;
        }

        #endregion

        #region DbContext

        protected readonly EfDbContextBase m_DbContext;

        #endregion

        #region Implement IRepository<T>

        public int Add(T model)
        {
            m_DbContext.Set<T>().Add(model);
            return m_DbContext.SaveChanges();
        }

        public int Update(T model)
        {
            // Update mutable info explictly when model is unchanged.
            var stateEntry = ((IObjectContextAdapter)m_DbContext).ObjectContext.ObjectStateManager.GetObjectStateEntry(model);
            if (stateEntry.State == System.Data.EntityState.Unchanged)
            {
                //m_DbContext.UpdateMutableInfo(model);
            }

            return m_DbContext.SaveChanges();
        }

        public int Delete(T model)
        {
            m_DbContext.Set<T>().Remove(model);
            return m_DbContext.SaveChanges();
        }

        public T Reload(T model)
        {
            var entry = m_DbContext.Entry<T>(model);
            entry.Reload();
            return entry.Entity;
        }

        public void Detach(T model)
        {
            m_DbContext.Detach(model);
        }

        public void Attach(T model)
        {
            var entry = m_DbContext.Entry<T>(model);
            if (entry.State == System.Data.EntityState.Detached)
            {
                m_DbContext.Set<T>().Attach(model);
                entry.State = System.Data.EntityState.Modified;
            }
        }

        public virtual IEnumerable<T> FindAll()
        {
            return m_DbContext.Set<T>();
        }

        public virtual IEnumerable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
        {
            return m_DbContext.Set<T>().Where(predicate);
        }

        public virtual TResult Excute<TResult>(System.Linq.Expressions.Expression<Func<IEnumerable<T>, TResult>> expression)
        {
            return expression.Compile()(m_DbContext.Set<T>());
        }

        #endregion
         
    }
    #endregion

    #region Class EntityRepository<TEntity, TID>
    public class EntityRepository<TEntity, TID> : EntityRepository<TEntity>, IRepository<TEntity, TID>
        where TEntity : class, IEntity<TID>
        where TID : IEquatable<TID>
    {
        public EntityRepository(EfDbContextBase dbContext) : base(dbContext)
        {
        }

        public TEntity FindByID(TID id)
        {
            return m_DbContext.Set<TEntity>().Where(entity => entity.ID.Equals(id)).SingleOrDefault();
        }

        public int Delete(TID id)
        {
            var entityToDelete = FindByID(id);
            if (entityToDelete == null)
                return 0;//todo Is this correct?
            m_DbContext.Set<TEntity>().Remove(entityToDelete);
            return m_DbContext.SaveChanges();
        }


        public int AddOrUpdate(TEntity model)
        {
            if (model.ID.Equals(default(TID)))
            {
                return Add(model);
            }
            else
            {
                return Update(model);
            }
        }
    }
    #endregion

    
}
